package model.persistencia.dao;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.Transient;

import org.hibernate.Query;
import org.hibernate.Session;

public class GenericDAO<T> {

	private Class persistentClass;

	public GenericDAO(Class persistentClass) {
		this.persistentClass = persistentClass;
	}

	protected Session getSession() {
		return HibernateUtil.getSession();
	}

	public T save(T t) {
		getSession().save(t);
		return t;
	}

	public void delete(T t) {
		getSession().delete(t);
	}

	public T merge(T t) {
		getSession().merge(t);
		return t;
	}

	@SuppressWarnings("unchecked")
	public List<T> list() {
		return getSession().createCriteria(persistentClass).list();
	}

	@SuppressWarnings("unchecked")
	public T load(Long id) {
		return (T) getSession().get(persistentClass, id);
	}

	@SuppressWarnings("unchecked")
	public void listar(Object bean, Query query, StringBuilder hql,
			HashMap<String, Object> parametros, String beanEntidade) throws Exception{

		Class classe = bean.getClass();

		Field[] atributos = classe.getDeclaredFields();

		for (Field atributo : atributos) {
			
		    Annotation transientAnnotation = atributo.getAnnotation(Transient.class);
			
		    if(transientAnnotation == null){
				Method metodo = null;
				
				String nomeAtributo = atributo.getName();

				String nomeMetodo = "get"
						+ nomeAtributo.substring(0, 1).toUpperCase()
						+ nomeAtributo.substring(1);

				metodo = classe.getMethod(nomeMetodo, new Class[0]);

				Object valor = null;

				valor = metodo.invoke(bean);

				if (valor != null && !valor.equals("")) {

					Annotation entidade = valor.getClass().getAnnotation(
							Entity.class);

					if (entidade != null) {

						beanEntidade = beanEntidade + "." + nomeAtributo;

						this.listar(valor, query, hql, parametros, beanEntidade);
						
						beanEntidade = beanEntidade.replaceAll("."+nomeAtributo, "");
						
					}else if (valor instanceof String) {
						hql.append(" and " + beanEntidade + ".");

						hql.append(nomeAtributo + " like :" + nomeAtributo);
						parametros.put(nomeAtributo, "%" + valor + "%");
					} else {
						hql.append(" and " + beanEntidade + ".");

						hql.append(nomeAtributo + " =:" + nomeAtributo);
						parametros.put(nomeAtributo, valor);
					}
				}
		    }
		}
	}

	public List<T> listar(Object bean) throws Exception {

		Query query = null;
		HashMap<String, Object> parametros = new HashMap<String, Object>();
		StringBuilder hql = new StringBuilder();

		hql = new StringBuilder();
		hql.append(" select bean from " + bean.getClass().getName() + " bean ");
		hql.append(" where 1 = 1 ");

		this.listar(bean, query, hql, parametros, "bean");

		query = getSession().createQuery(hql.toString());
		query.setProperties(parametros);

		List<T> list = query.list();

		return (List<T>) list;

	}
	
	public List<T> listar(String hql, HashMap<String, Object> parametros){
		
		Query query = getSession().createQuery(hql);
		query.setProperties(parametros);
		
		List<T> list = query.list();
		
		return list;	
	}

}